#include "../include/CL_compiler.h"

CL_compiler::CL_compiler(const char * name)
{
    cl::Context context(CL_DEVICE_TYPE_GPU, NULL, NULL, NULL, &err);
    checkErr(err, "Conext::Context()");
    contptr = &context;

    file.open(name);

    size_t length;
    length = file.tellg();
    buffer = new char[length];
    file.read(buffer, length);
    std::string prog(buffer, length);

    devices = context.getInfo<CL_CONTEXT_DEVICES>();
    checkErr(devices.size() > 0 ? CL_SUCCESS : -1, "devices.size() > 0");

    cl::Program::Sources source(1, make_pair(prog.c_str(), prog.length()+1));
    cl::Program program(context, source);

    err = program.build(devices,"");
    checkErr(err, "Program::build()");

    cl::Kernel kernel(program, "hello", &err);
    checkErr(err, "Kernel::Kernel()");
    kernptr = &kernel;
}

CL_compiler::~CL_compiler()
{
    delete[] buffer;
    file.close();
}

inline void CL_compiler::checkErr(cl_int err, const char * name)
{
    if(err != CL_SUCCESS){
        cerr << "error: " << name << " (" << err << ")" << endl;
        exit(EXIT_FAILURE);
    }
}

double CL_compiler::compute(op ops)
{
    err = kernptr->setArg(0, retv);
    checkErr(err, "Kernel::setArg(0)");
    err = kernptr->setArg(1, &ops.size);
    checkErr(err, "Kernel::setArg(1)");
    err = kernptr->setArg(2, &ops.bounds.first);
    checkErr(err, "Kernel::setArg(2)");

    cl::CommandQueue queue(*contptr, devices[0], 0, &err);
    checkErr(err, "CommandQueue::CommandQueue()");

    err = queue.enqueueNDRangeKernel(*kernptr,
                                     cl::NDRange(0),
                                     cl::NDRange((ops.bounds.first - ops.bounds.second)*ops.size),
                                     cl::NullRange,
                                     NULL,
                                     &event);
    checkErr(err, "ComandQueue::enqueueNDRangeKernel()");

    event.wait();


    return *retv;
}

void CL_compiler::invoke()
{

}